package com.noahplat.oauth.service.impl;

import com.noahplat.common.utils.Result;
import com.noahplat.common.utils.StatusCode;
import com.noahplat.common.utils.TokenDecode;
import com.noahplat.oauth.service.UserLoginService;
import com.noahplat.oauth.utils.AuthToken;
import com.noahplat.oauth.utils.LoginParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.*;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * 作者：李景星
 * 描述：用户登录封装实现类
 * 时间：2020-11-02
 */
@Service
public class UserLoginServiceImpl implements UserLoginService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    /**
     * 作者：李景星
     * 描述：用户登录功能封装
     * 时间：2020-11-02
     * @param loginParam
     * @param clientId
     * @param clientSecret
     * @return
     */
    @Override
    public Result<AuthToken> login(LoginParam loginParam, String clientId, String clientSecret) {
        //获取认证服务地址实例
        ServiceInstance serviceInstance = loadBalancerClient.choose("oauth");
        if(ObjectUtils.isEmpty(serviceInstance)){
            return new Result(true, StatusCode.ERROR, "获取令牌失败");
        }
        //拼接令牌获取的url
        String path = serviceInstance.getUri().toString()+"/oauth/token";
        //定义body
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        //授权方式
        formData.add("grant_type", "password");
        //账号
        formData.add("username", loginParam.getUsername());
        //密码
        formData.add("password", loginParam.getPassword());
        //定义头
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        header.add("Authorization", httpbasic(clientId, clientSecret));
        //请求/oauth/token获取令牌
        //http请求spring security的申请令牌接口
        ResponseEntity<Map> mapResponseEntity = null;
        try {
            mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class);
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false, StatusCode.ERROR, "用户名或密码错误");
        }
        Map map = mapResponseEntity.getBody();
        if(map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) {
            return new Result(false, StatusCode.ERROR, "获取令牌失败");
        }
        //移动端登录账号和PC端登录账号隔离登录，需判断登录标识
        Map<String, String> userInfo = TokenDecode.dcodeToken((String) map.get("access_token"));
        if(!loginParam.getUserType().equals(userInfo.get("userType"))){
            return new Result(false, StatusCode.UNAUTHORIZED, "当前用户无权登录");
        }
        //判断当前登录账户系统标识是否允许登录不同系统账号隔离
        String s = userInfo.get("stid");
        String str = loginParam.getStid();
        if(!loginParam.getStid().equals(userInfo.get("stid"))){
            return new Result(false, StatusCode.ERROR, "用户名或密码错误");
        }
        //封装token对象
        AuthToken authToken = new AuthToken();
        //访问令牌(jwt)
        String accessToken = (String) map.get("access_token");
        //刷新令牌(jwt)
        String refreshToken = (String) map.get("refresh_token");
        //jti，作为用户的身份标识
        String jwtToken= (String) map.get("jti");
        authToken.setJti(jwtToken);
        authToken.setAccessToken(accessToken);
        authToken.setRefreshToken(refreshToken);
        return new Result<AuthToken>(true, StatusCode.OK, "获取令牌成功", authToken);
    }

    /**
     * 刷新token
     * @param refreshToken
     * @param clientId
     * @param clientSecret
     * @return
     */
    @Override
    public Result<AuthToken> refreshToken(String refreshToken, String clientId, String clientSecret) {
        //获取认证服务地址实例
        ServiceInstance serviceInstance = loadBalancerClient.choose("oauth");
        if(ObjectUtils.isEmpty(serviceInstance)){
            return new Result(true, StatusCode.ERROR, "获取令牌失败");
        }
        //拼接令牌获取的url
        String path = serviceInstance.getUri().toString()+"/oauth/token";
        //定义body
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        //授权方式
        formData.add("grant_type", "refresh_token");
        //刷新token
        formData.add("refresh_token", refreshToken);
        //定义头
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        header.add("Authorization", httpbasic(clientId, clientSecret));
        //请求/oauth/token获取令牌
        //http请求spring security的申请令牌接口
        ResponseEntity<Map> mapResponseEntity = null;
        try {
            mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class);
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false, StatusCode.ERROR, "获取令牌失败");
        }
        Map map = mapResponseEntity.getBody();
        if(map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) {
            return new Result(false, StatusCode.ERROR, "获取令牌失败");
        }
        //封装token对象
        AuthToken authToken = new AuthToken();
        //访问令牌(jwt)
        String newAccessToken = (String) map.get("access_token");
        //刷新令牌(jwt)
        String newRefreshToken = (String) map.get("refresh_token");
        //jti，作为用户的身份标识
        String newJwtToken= (String) map.get("jti");
        authToken.setJti(newJwtToken);
        authToken.setAccessToken(newAccessToken);
        authToken.setRefreshToken(newRefreshToken);
        return new Result<AuthToken>(true, StatusCode.OK, "获取令牌成功", authToken);
    }

    /***
     * 作者：李景星
     * 描述：httpbasic拼接工具类
     * 时间：2020-11-02
     * @param clientId
     * @param clientSecret
     * @return
     */
    private String httpbasic(String clientId,String clientSecret){
        //将客户端id和客户端密码拼接，按“客户端id:客户端密码”
        String string = clientId+":"+clientSecret;
        //进行base64编码
        byte[] encode = Base64Utils.encode(string.getBytes());
        return "Basic "+new String(encode);
    }
}
